#include "WhileBuilder.h"

#include "ScriptCompiler/ScriptFileContext.h"

#include "ScriptCompiler/AST/WhileNode.h"
#include "ScriptCompiler/ASTBuilder/ExpressionBuilder.h"
#include "ScriptCompiler/ASTBuilder/SentenceBlockBuilder.h"

CWhileBuilder::CWhileBuilder(std::shared_ptr<CScriptFileContext> InContext)
{
    Context = InContext;
    Result = std::make_shared<CWhileNode>(InContext);
}

bool CWhileBuilder::ReadCurentToken()
{

    //read 'while'
    {
        auto Token = Context->GetCurrentToken();
        if (Token->Type != EScriptTokenType::While)
        {
            Context->RaiseError(10136,Token, U"Expect 'while' here");
            return false;
        }
        Result->While = Token;
        Context->CurrentTokenIndex++;
    }

    //read '('
    {
        auto Token = Context->GetCurrentToken();
        if (Token->Type != EScriptTokenType::LeftParentheses)
        {
            Context->RaiseError(10137,Token, U"Expect '(' here");
            return false;
        }
        //Result->LeftParentheses = Token;
        Context->CurrentTokenIndex++;
    }

    //find ')'
    uint64_t RightParenthesesIndex;
    {
        auto RightParenthesesPos = FindPairedParentheses(Context);
        if (!RightParenthesesPos)
        {
            //raise error, require ')'
            Context->RaiseError(10138,Context->GetCurrentToken(), U"Expected paired ')' ");
            return false;
        }
        RightParenthesesIndex = *RightParenthesesPos;
    }

    //read condition
    {
        auto ExpressionBuilder = std::make_shared<CExpressionBuilder>(Context,RightParenthesesIndex);
        if (!ExpressionBuilder->ReadCurentToken())
        {
            return false;
        }
        Result->Condition = ExpressionBuilder->Result;
    }

    //read ')'
    {
        auto Token = Context->GetCurrentToken();
        if (Token->Type != EScriptTokenType::RightParentheses)
        {
            Context->RaiseError(10139,Token, U"Expect ')' here");
            return false;
        }
        //Result->RightParentheses = Token;
        Context->CurrentTokenIndex++;
    }

    //make sure next token is '{'
    {
        auto Token = Context->GetCurrentToken();
        if (Token->Type != EScriptTokenType::LeftBrace)
        {
            Context->RaiseError(10153,Token, U"Expect '{' after 'while', do not allow loop body without '{ }'");
            return false;
        }
        //Result->LeftBrace = Token;
        Context->CurrentTokenIndex++;
    }

    //find '}'
    uint64_t RightBraceIndex;
    {
        auto RightBracePos = FindPairedBrace(Context);
        if (!RightBracePos)
        {
            //raise error, require '}'
            Context->RaiseError(10154,Context->GetCurrentToken(), U"Expected paired '}' ");
            return false;
        }
        RightBraceIndex = *RightBracePos;
    }

    //read body 
    {
        auto SentenceBlockBuilder = std::make_shared<CSentenceBlockBuilder>(Context,RightBraceIndex);
        if (!SentenceBlockBuilder->ReadCurentToken())
        {
            return false;
        }
        Result->Body = SentenceBlockBuilder->Result;
    }

    //skip }
    assert(Context->CurrentTokenIndex==RightBraceIndex);
    Context->CurrentTokenIndex++;

    return true;

}
